#include <accent/algorithms/map.hpp>
#include "test_base.hpp"

struct x {
  int i;

  x(int i) : i(i) {}
};

typedef std::vector<x> xvec;

struct xi {
  const int& operator ()(const x& y) const { return y.i; }
  int& operator ()(x& y) const { return y.i; }
};

auto mapxi(xvec& v) -> decltype(map(all(v), xi()))
{
  return map(all(v), xi());
}

TEST(Map, emptyRange_isEmpty) {
  xvec v = {};
  auto r = mapxi(v);
  ASSERT_TRUE(r.empty());
}

TEST(Map, oneElement_notEmpty) {
  xvec v = { 1 };
  auto r = mapxi(v);
  ASSERT_FALSE(r.empty());
}

TEST(Map, oneElement_frontIsMemberValue) {
  xvec v = { 1 };
  auto r = mapxi(v);
  ASSERT_EQ(1, r.front());
}

TEST(Map, oneElement_frontIsAssignable) {
  xvec v = { 1 };
  auto r = mapxi(v);
  r.front() = 2;
  ASSERT_EQ(2, v.front().i);
}

TEST(Map, oneElement_popFront_makesEmpty) {
  xvec v = { 1 };
  auto r = mapxi(v);
  r.pop_front();
  ASSERT_TRUE(r.empty());
};

TEST(Map, twoElements_popFront_frontIsSecondMemberValue) {
  xvec v = { 1, 2 };
  auto r = mapxi(v);
  r.pop_front();
  ASSERT_EQ(2, r.front());
}

TEST(Map, oneElement_backIsMemberValue) {
  xvec v = { 1 };
  auto r = mapxi(v);
  ASSERT_EQ(1, r.back());
}

TEST(Map, twoElements_backIsSecondMemberValue) {
  xvec v = { 1, 2 };
  auto r = mapxi(v);
  ASSERT_EQ(2, r.back());
}

TEST(Map, oneElement_backIsAssignable) {
  xvec v = { 1 };
  auto r = mapxi(v);
  r.back() = 2;
  ASSERT_EQ(2, v.front().i);
}

TEST(Map, oneElement_popBack_makesEmpty) {
  xvec v = { 1 };
  auto r = mapxi(v);
  r.pop_back();
  ASSERT_TRUE(r.empty());
};

TEST(Map, twoElements_popBack_backIsFirstMemberValue) {
  xvec v = { 1, 2 };
  auto r = mapxi(v);
  r.pop_back();
  ASSERT_EQ(1, r.back());
}

TEST(Map, emptyRange_sizeIsZero) {
  xvec v = {};
  auto r = mapxi(v);
  ASSERT_EQ(0, r.size());
}

TEST(Map, threeElements_sizeIsThree) {
  xvec v = { 1, 2, 3 };
  auto r = mapxi(v);
  ASSERT_EQ(3, r.size());
}

TEST(Map, indexingIsCorrect) {
  xvec v = { 1, 2, 3 };
  auto r = mapxi(v);
  ASSERT_EQ(1, r[0]);
  ASSERT_EQ(2, r[1]);
  ASSERT_EQ(3, r[2]);
}

TEST(Map, threeElements_skipFrontTwo_frontIsLast) {
  xvec v = { 1, 2, 3 };
  auto r = mapxi(v);
  r.skip_front(2);
  ASSERT_EQ(3, r.front());
}

TEST(Map, threeElements_skipBackTwo_backIsFirst) {
  xvec v = { 1, 2, 3 };
  auto r = mapxi(v);
  r.skip_back(2);
  ASSERT_EQ(1, r.back());
}
